class QueryBuilder {
  constructor() {
    this.conditions = {};
    this.limit = null;
    this.offset = null;
    this.groupBy = null;
  }

  where(condition, ...params) {
    this.conditions[condition] = params;
    return this;
  }

  setLimit(limit) {
    this.limit = limit;
    return this;
  }

  setOffset(offset) {
    this.offset = offset;
    return this;
  }

  setGroupBy(groupBy) {
    this.groupBy = groupBy;
    return this;
  }

  sqdata(sql, params) {
    console.log(sql, params)
    return new Promise((resolve, reject) => {
      global.sql.query(sql, params, (err, result) => {
        if (err) {
          console.log(err.message);
          reject(err);
        }
        resolve(result);
      });
    });
  }

  getParams() {
    return Object.values(this.conditions).flat();
  }

  buildConditions() {
    return Object.keys(this.conditions).map(condition => `${condition}`).join(' AND ');
  }
}

class SelectBuilder extends QueryBuilder {
  constructor() {
    super();
    this.selectFields = [];
    this.tables = [];
    this.orderByField = '';
    this.orderByDirection = 'ASC';
  }

  select(fields) {
    this.selectFields = fields.split(',').map(field => field.trim());
    return this;
  }

  from(table) {
    this.tables.push(table);
    return this;
  }

  leftJoin(table, condition) {
    this.tables.push(`LEFT JOIN ${table} ON ${condition}`);
    return this;
  }

  orderBy(field, direction = 'ASC') {
    this.orderByField = field;
    this.orderByDirection = direction.toUpperCase();
    return this;
  }

  async build() {
    let sql = `SELECT ${this.selectFields.join(', ')} FROM ${this.tables.join(' ')}`;
    let conditionClauses = this.buildConditions();
    if (conditionClauses) {
      sql += ` WHERE ${conditionClauses}`;
    }
    if (this.orderByField) {
      sql += ` ORDER BY ${this.orderByField} ${this.orderByDirection}`;
    }
    if (this.limit !== null) {
      sql += ` LIMIT ${this.limit}`;
    }
    if (this.offset !== null) {
      sql += ` OFFSET ${this.offset}`;
    }
    console.log(sql)
    return await this.sqdata(sql, this.getParams());
  }
}

class UpdateBuilder extends QueryBuilder {
  constructor() {
    super();
    this.table = '';
    this.updateFields = {};
  }

  update(table) {
    this.table = table;
    return this;
  }

  set(field, value) {
    this.updateFields[field] = value;
    return this;
  }

  async build() {
    let sql = `UPDATE ${this.table} SET ${Object.keys(this.updateFields).map(field => `${field} = ?`).join(', ')}`;
    let conditionClauses = this.buildConditions();
    if (conditionClauses) {
      sql += ` WHERE ${conditionClauses}`;
    }
    const params = [...Object.values(this.updateFields), ...this.getParams()];
    return await this.sqdata(sql, params);
  }
}

class InsertBuilder extends QueryBuilder {
  constructor() {
    super();
    this.table = '';
    this.insertValues = {};
  }

  insertInto(table) {
    this.table = table;
    return this;
  }

  values(values) {
    this.insertValues = values;
    return this;
  }

  async build() {
    let sql = `INSERT INTO ${this.table} (${Object.keys(this.insertValues).join(', ')}) VALUES (${Object.keys(this.insertValues).map(() => '?').join(', ')})`;
    const params = Object.values(this.insertValues);
    return await this.sqdata(sql, params);
  }
}

class DeleteBuilder extends QueryBuilder {
  constructor() {
    super();
    this.table = '';
  }

  deleteFrom(table) {
    this.table = table;
    return this;
  }

  async build() {
    let sql = `DELETE FROM ${this.table}`;
    let conditionClauses = this.buildConditions();
    if (conditionClauses) {
      sql += ` WHERE ${conditionClauses}`;
    }
    return await this.sqdata(sql, this.getParams());
  }
}

module.exports = {
  SelectBuilder,
  UpdateBuilder,
  InsertBuilder,
  DeleteBuilder,
};
